from flask import g
import time
import pigpio
import util
import config


class Dht22:
    def __init__(self, channel):
        self.pi = g.pi
        self.channel = channel
        self.process = None
        self.data = []
        self.high_tick = 0
        self.bits_count = -3

        # 初始化 上拉电阻所以默认高电平
        self.pi.set_pull_up_down(channel, pigpio.PUD_OFF)
        self.pi.set_watchdog(channel, 0)

        # 电平变化触发回调process函数 注意set_watchdog
        self.process = self.pi.callback(channel, pigpio.EITHER_EDGE, self._process)

    def _process(self, channel, level, tick):
        # 上个电位变化的实践
        diff = pigpio.tickDiff(self.high_tick, tick)

        # 拉低 则上个电位是高电位，可以用来计算01数值
        if level == 0:
            self.bits_count += 1

            # 文档描述的时间是70us
            if diff >= 50:
                # 二进制1
                val = 1
                # 大于100可能出错 标记错误
                if diff >= 100:
                    self.bad_checksum = 256
            else:
                # 文档描述时间为16-28us
                # 二进制0
                val = 0

            # 要经历3次低电平，第四次时为data bits
            if self.bits_count >= 1:
                self.data.append(val)

        # 拉高
        elif level == 1:
            self.high_tick = tick

        # 电平没有变化但是 watchdog 超时
        else:
            self.pi.set_watchdog(self.channel, 0)

    def trigger(self):
        # 触发温湿度读取
        self.pi.write(self.channel, pigpio.LOW)
        time.sleep(0.001)  # 1000 us
        self.pi.set_mode(self.channel, pigpio.INPUT)
        self.pi.set_watchdog(self.channel, 200)

    def cancel(self):
        # 重置
        self.process.cancel()
        self.pi.set_watchdog(self.channel, 0)
        self.process = None

    def check_sum(self):
        bits_list = list(util.list_chunk(self.data, 8))
        _sum = int(util.list_join(bits_list[0]), 2) + int(util.list_join(bits_list[1]), 2) + int(util.list_join(bits_list[2]), 2) + int(util.list_join(bits_list[3]), 2)
        return (_sum & 255) == int(util.list_join(bits_list[4]), 2)

    def get_data(self):
        # 验证位错误
        if self.check_sum() is False:
            return {'temperature': None, 'humidity': None}
        # 成功
        bits_list = list(util.list_chunk(self.data, 16))
        humidity = int(util.list_join(bits_list[0]), 2)/10
        temperature = int(util.list_join(bits_list[1]), 2)/10
        return {'temperature': temperature, 'humidity': humidity}


# 调用请建个2秒以上
def get_data():
    if config.env is not 'prod':
        return {'temperature': None, 'humidity': None}

    dht22 = Dht22(channel=4)
    dht22.trigger()

    # 等待数据读取
    time.sleep(0.1)
    dht22.cancel()

    return dht22.get_data()
